package utils;
import java.io.UnsupportedEncodingException;

/**
 * Certains fonctions usuels pour l'utilsation des nombres binaires.
 * 
 * @author Bertholet Damien & Daoust Julien
 */
public class BinaryOperation {

	private static final String charsetEncodage = "UTF-8";

	/**
	 * Convertit une string en string binaire.
	 * 
	 * @param string
	 *            La string a convertir.
	 * @return La string binaire convertit.
	 */
	public static String convertStringToBinary(String string) {
		byte[] bytes;
		try {
			bytes = string.getBytes(BinaryOperation.charsetEncodage);
		} catch (UnsupportedEncodingException e) {
			// Cela n'arrivera pas car cet encodage est supporte par la version
			// de Java utilise.
			return null;
		}

		return BinaryOperation.convertBytesToBinary(bytes);
	}

	/**
	 * Convertit une string binaire en string.
	 * 
	 * @param binaryString
	 *            La string binaire a convertir.
	 * @return La string convertit.
	 */
	public static String convertBinaryToString(String binaryString) {
		try {
			byte[] bytes = BinaryOperation.convertBinaryToBytes(binaryString);
			return new String(bytes, BinaryOperation.charsetEncodage);
		} catch (UnsupportedEncodingException e) {
			// Cela n'arrivera pas car cet encodage est supporte par la version
			// de Java utilise.
			return null;
		}
	}

	/**
	 * Convertit un tableau de {@link Byte} en une string binaire.
	 * 
	 * @param bytes
	 *            Le tableau de {@link Byte}.
	 * @return La string binaire.
	 */
	private static String convertBytesToBinary(byte[] bytes) {
		String binaryString = "";
		for(byte b: bytes) {
			String binary = Integer.toBinaryString(b & 0xFF);
			binaryString += BinaryOperation.ajustSize(binary, 8);
		}

		return binaryString;
	}

	/**
	 * Convertit une string binaire en tableau de {@link Byte}.
	 * 
	 * @param binaryString
	 *            La string binaire.
	 * @return Le tableau de {@link Byte}.
	 */
	private static byte[] convertBinaryToBytes(String binaryString) {
		int nbrByte = binaryString.length() / 8;
		byte[] bytes = new byte[nbrByte];

		for(int i = 0 ; i < nbrByte ; i++) {
			int begin = i * 8;
			String binaryValue = binaryString.substring(begin, begin + 8);

			int value = Integer.parseInt(binaryValue, 2);
			bytes[i] = (byte) value;
		}

		return bytes;
	}

	/**
	 * Effectue un xor (ou exclusif) sur les deux strings binaire. Le resultat
	 * sera une chaine binaire.
	 * 
	 * @param binaryString1
	 *            La chaine binaire 1.
	 * @param binaryString2
	 *            La chaine binaire 2.
	 * @return Le xor (ou exclusif) sur les deux strings binaire.
	 */
	public static String XoR(String binaryString1, String binaryString2) {
		int minSize = Math.min(binaryString1.length(), binaryString2.length());
		String rest = "";
		for(int i = 0 ; i < minSize ; i++) {
			char binaryStringChar1 = binaryString1.charAt(i);
			char binaryStringChar2 = binaryString2.charAt(i);

			if(binaryStringChar1 == binaryStringChar2)
				rest += "0";
			else
				rest += "1";
		}

		if(binaryString1.length() > binaryString2.length())
			return rest + binaryString1.substring(minSize);
		else if(binaryString1.length() < binaryString2.length())
			return rest + binaryString2.substring(minSize);
		else
			return rest;
	}

	/**
	 * Ajuste la string binaire a la taille donnee en ajoutant des zeros devant.
	 * Si la string est plus grand que la taille demandee, une
	 * {@link IllegalArgumentException} sera lance.
	 * 
	 * @param binaryString
	 *            La string binaire.
	 * @param size
	 *            La taille que dois faire la string binaire.
	 * @return La string binaire avec la bonne taille.
	 */
	public static String ajustSize(String binaryString, int size) {
		if(binaryString.length() > size)
			throw new IllegalArgumentException();

		String temp = binaryString;
		while(temp.length() < size)
			temp = "0" + temp;

		return temp;
	}

	/**
	 * Supprime les 0 qui se situe a gauche de la string binaire. Si la string
	 * binaire ne contient que des '0', il en laissera un seul.
	 * 
	 * @param binaryString
	 *            La string binaire.
	 * @return La nouvelle string binaire.
	 */
	public static String removeLeftZero(String binaryString) {
		while(binaryString.startsWith("0") && binaryString.length() > 1)
			binaryString = binaryString.substring(1);
		return binaryString;
	}

	/**
	 * Multiplie par deux le nombre binaire 'nb' fois. Ceci ajoute des '0' a la
	 * droite de la string binaire 'nb' fois.
	 * 
	 * @param binaryString
	 *            La string binaire.
	 * @param nb
	 *            Le nombre de fois que le nombre sera multiplie par deux.
	 * @return La string binaire multiplie par deux 'nb' fois.
	 */
	public static String mulBy2(String binaryString, int nb) {
		String temp = binaryString;
		for(int i = 0 ; i < nb ; i++)
			temp += "0";

		return temp;
	}
}